import { LOG } from '../../../ConsoleLogCtrl';
import { MessageType, IMessage, IMessageSubscriber } from './MessageTypes';

/**
 * 消息分发器
 * 负责消息的订阅、取消订阅和分发功能
 */
export class MessageDispatcher {
    /** 消息订阅者映射表 */
    private subscribers: Map<MessageType, IMessageSubscriber[]> = new Map();
    
    /** 分发统计信息 */
    private statistics: {
        totalDispatched: number;
        dispatchErrors: number;
        lastDispatchTime: number;
    } = {
        totalDispatched: 0,
        dispatchErrors: 0,
        lastDispatchTime: 0
    };
    
    /**
     * 订阅消息
     * @param type 消息类型
     * @param callback 回调函数
     * @param target 目标对象（可选，用于批量取消订阅）
     */
    public subscribe<T = any>(
        type: MessageType, 
        callback: (message: IMessage<T>) => void, 
        target?: any
    ): void {
        if (!this.subscribers.has(type)) {
            this.subscribers.set(type, []);
        }
        
        const subscriber: IMessageSubscriber = {
            callback: callback as (message: IMessage<any>) => void,
            target,
            subscribeTime: Date.now()
        };
        
        const subscriberList = this.subscribers.get(type)!;
        
        // 检查是否已经订阅过相同的回调
        const existingIndex = subscriberList.findIndex(sub => 
            sub.callback === callback && sub.target === target
        );
        
        if (existingIndex === -1) {
            subscriberList.push(subscriber);
            LOG.log(`订阅消息: ${type}, 当前订阅者数量: ${subscriberList.length}`);
        } else {
            LOG.warn(`重复订阅消息: ${type}`);
        }
    }
    
    /**
     * 取消订阅消息
     * @param type 消息类型
     * @param callback 回调函数（可选）
     * @param target 目标对象（可选）
     */
    public unsubscribe<T = any>(
        type: MessageType, 
        callback?: (message: IMessage<T>) => void, 
        target?: any
    ): void {
        const subscriberList = this.subscribers.get(type);
        if (!subscriberList) {
            return;
        }
        
        if (callback) {
            // 取消特定回调的订阅
            const index = subscriberList.findIndex(sub => 
                sub.callback === callback && sub.target === target
            );
            
            if (index !== -1) {
                subscriberList.splice(index, 1);
                LOG.log(`取消订阅消息: ${type}, 剩余订阅者数量: ${subscriberList.length}`);
            }
        } else if (target) {
            // 取消目标对象的所有订阅
            const originalLength = subscriberList.length;
            const filteredList = subscriberList.filter(sub => sub.target !== target);
            
            this.subscribers.set(type, filteredList);
            const removedCount = originalLength - filteredList.length;
            
            if (removedCount > 0) {
                LOG.log(`取消目标对象订阅: ${type}, 移除${removedCount}个订阅者`);
            }
        } else {
            // 清空该类型的所有订阅
            this.subscribers.set(type, []);
            LOG.log(`清空消息订阅: ${type}`);
        }
        
        // 如果没有订阅者了，删除该类型
        if (subscriberList.length === 0) {
            this.subscribers.delete(type);
        }
    }
    
    /**
     * 取消目标对象的所有消息订阅
     * @param target 目标对象
     */
    public unsubscribeTarget(target: any): void {
        if (!target) {
            return;
        }
        
        let totalRemoved = 0;
        
        for (const [type, subscriberList] of this.subscribers.entries()) {
            const originalLength = subscriberList.length;
            const filteredList = subscriberList.filter(sub => sub.target !== target);
            
            this.subscribers.set(type, filteredList);
            const removedCount = originalLength - filteredList.length;
            totalRemoved += removedCount;
            
            // 如果没有订阅者了，删除该类型
            if (filteredList.length === 0) {
                this.subscribers.delete(type);
            }
        }
        
        if (totalRemoved > 0) {
            LOG.log(`取消目标对象所有订阅，共移除${totalRemoved}个订阅者`);
        }
    }
    
    /**
     * 分发消息
     * @param message 消息对象
     */
    public dispatch<T = any>(message: IMessage<T>): void {
        const subscriberList = this.subscribers.get(message.type);
        if (!subscriberList || subscriberList.length === 0) {
            return;
        }
        
        this.statistics.lastDispatchTime = Date.now();
        
        // 创建订阅者列表的副本，避免在回调中修改订阅者列表时出现问题
        const subscribersCopy = [...subscriberList];
        
        for (const subscriber of subscribersCopy) {
            try {
                // 检查目标对象是否仍然有效
                if (subscriber.target && this.isTargetValid(subscriber.target)) {
                    subscriber.callback(message);
                } else if (!subscriber.target) {
                    // 没有目标对象的订阅者直接调用
                    subscriber.callback(message);
                }
                
                this.statistics.totalDispatched++;
            } catch (error) {
                LOG.error(`消息分发错误 [${message.type}]:`, error);
                this.statistics.dispatchErrors++;
                
                // 可选：移除出错的订阅者
                this.removeInvalidSubscriber(message.type, subscriber);
            }
        }
    }
    
    /**
     * 检查目标对象是否有效
     * @param target 目标对象
     */
    private isTargetValid(target: any): boolean {
        if (!target) {
            return false;
        }
        
        // 检查Cocos Creator节点是否有效
        if (target.node && target.node.isValid !== undefined) {
            return target.node.isValid;
        }
        
        // 检查节点是否有效
        if (target.isValid !== undefined) {
            return target.isValid;
        }
        
        // 其他对象默认有效
        return true;
    }
    
    /**
     * 移除无效的订阅者
     * @param type 消息类型
     * @param invalidSubscriber 无效的订阅者
     */
    private removeInvalidSubscriber(type: MessageType, invalidSubscriber: IMessageSubscriber): void {
        const subscriberList = this.subscribers.get(type);
        if (!subscriberList) {
            return;
        }
        
        const index = subscriberList.indexOf(invalidSubscriber);
        if (index !== -1) {
            subscriberList.splice(index, 1);
            LOG.warn(`移除无效订阅者: ${type}`);
            
            // 如果没有订阅者了，删除该类型
            if (subscriberList.length === 0) {
                this.subscribers.delete(type);
            }
        }
    }
    
    /**
     * 获取指定类型的订阅者数量
     * @param type 消息类型
     */
    public getSubscriberCount(type: MessageType): number {
        const subscriberList = this.subscribers.get(type);
        return subscriberList ? subscriberList.length : 0;
    }
    
    /**
     * 获取所有订阅者总数
     */
    public getTotalSubscriberCount(): number {
        let total = 0;
        for (const subscriberList of this.subscribers.values()) {
            total += subscriberList.length;
        }
        return total;
    }
    
    /**
     * 获取所有消息类型
     */
    public getMessageTypes(): MessageType[] {
        return Array.from(this.subscribers.keys());
    }
    
    /**
     * 检查是否有指定类型的订阅者
     * @param type 消息类型
     */
    public hasSubscribers(type: MessageType): boolean {
        return this.getSubscriberCount(type) > 0;
    }
    
    /**
     * 获取分发统计信息
     */
    public getStatistics(): {
        totalDispatched: number;
        dispatchErrors: number;
        lastDispatchTime: number;
        totalSubscribers: number;
        messageTypes: number;
    } {
        return {
            ...this.statistics,
            totalSubscribers: this.getTotalSubscriberCount(),
            messageTypes: this.subscribers.size
        };
    }
    
    /**
     * 重置统计信息
     */
    public resetStatistics(): void {
        this.statistics = {
            totalDispatched: 0,
            dispatchErrors: 0,
            lastDispatchTime: 0
        };
    }
    
    /**
     * 清空所有订阅者
     */
    public clear(): void {
        const totalSubscribers = this.getTotalSubscriberCount();
        this.subscribers.clear();
        this.resetStatistics();
        
        if (totalSubscribers > 0) {
            LOG.log(`清空所有消息订阅者，共${totalSubscribers}个`);
        }
    }
    
    /**
     * 调试信息：打印所有订阅信息
     */
    public debugPrintSubscriptions(): void {
        LOG.log('=== 消息订阅信息 ===');
        for (const [type, subscriberList] of this.subscribers.entries()) {
            LOG.log(`${type}: ${subscriberList.length}个订阅者`);
            subscriberList.forEach((sub, index) => {
                const targetInfo = sub.target ? sub.target.constructor.name : 'No Target';
                LOG.log(`  [${index}] Target: ${targetInfo}, 订阅时间: ${new Date(sub.subscribeTime).toLocaleTimeString()}`);
            });
        }
        LOG.log('==================');
    }
}